home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / ddj1191.zip / GRPHPROG.ASC < prev    next >
Text File  |  1991-10-18  |  26KB  |  579 lines

  1. _GRAPHICS PROGRAMMING COLUMN_
  2. by Michael Abrash
  3.  
  4. [LISTING ONE]
  5.  
  6. /* Looks for a Sierra Hicolor DAC; if one is present, puts the VGA into the 
  7. specified Hicolor (32K color) mode. Relies on the Tseng Labs ET4000 BIOS and 
  8. hardware; probably will not work on adapters built around other VGA chips. 
  9. Returns 1 for success, 0 for failure; failure can result from no Hicolor DAC, 
  10. too little display memory, or lack of an ET4000. Tested with Borland C++ 2.
  11. 0 in C mode in the small model. */
  12.  
  13. #include <dos.h>
  14. #define DAC_MASK  0x3C6 /* DAC pixel mask reg address, also Sierra
  15.                            command reg address when enabled */
  16. #define DAC_WADDR 0x3C8  /* DAC write address reg address */
  17.  
  18. /* Mode selections: 0x2D=640x350; 0x2E=640x480; 0x2F=640x400; 0x30=800x600 */
  19. int SetHCMode(int Mode) {
  20.    int i, Temp1, Temp2, Temp3;
  21.    union REGS regset;
  22.  
  23.    /* See if a Sierra SC1148X Hicolor DAC is present, by trying to
  24.    program and then read back the DAC's command register. (Shouldn't be 
  25.    necessary when using the BIOS Get DAC Type function, but the BIOS function 
  26.    locks up some computers, so it's safer to check the hardware first) */
  27.    inp(DAC_WADDR); /* reset the Sierra command reg enable sequence */
  28.    for (i=0; i<4; i++) inp(DAC_MASK); /* enable command reg access */
  29.    outp(DAC_MASK, 0x00); /* set command reg (if present) to 0x00, and
  30.                             reset command reg enable sequence */
  31.    outp(DAC_MASK, 0xFF); /* command reg access no longer enabled;
  32.                             set pixel mask register to 0xFF */
  33.    for (i=0; i<4; i++) inp(DAC_MASK); /* enable command reg access */
  34.    /* If this is a Hicolor DAC, we should read back the 0 in the
  35.       command reg; otherwise we get the 0xFF in the pixel mask reg */
  36.    i = inp(DAC_MASK); inp(DAC_WADDR); /* reset enable sequence */
  37.    if (i == 0xFF) return(0);
  38.  
  39.    /* Check for a Tseng Labs ET4000 by poking unique regs, (assumes
  40.       VGA configured for color, w/CRTC addressing at 3D4/5) */
  41.    outp(0x3BF, 3); outp(0x3D8, 0xA0);  /* unlock extended registers */
  42.    /* Try toggling AC R16 bit 4 and seeing if it takes */
  43.    inp(0x3DA); outp(0x3C0, 0x16 | 0x20);
  44.    outp(0x3C0, ((Temp1 = inp(0x3C1)) | 0x10)); Temp2 = inp(0x3C1);
  45.    outp(0x3C0, 0x16 | 0x20); outp(0x3C0, (inp(0x3C1) & ~0x10));
  46.    Temp3 = inp(0x3C1); outp(0x3C0, 0x16 | 0x20);
  47.    outp(0x3C0, Temp1);  /* restore original AC R16 setting */
  48.    /* See if the bit toggled; if so, it's an ET3000 or ET4000 */
  49.    if ((Temp3 & 0x10) || !(Temp2 & 0x10)) return(0);
  50.    outp(0x3D4, 0x33); Temp1 = inp(0x3D5); /* get CRTC R33 setting */
  51.    outp(0x3D5, 0x0A); Temp2 = inp(0x3D5); /* try writing to CRTC */
  52.    outp(0x3D5, 0x05); Temp3 = inp(0x3D5); /*  R33 */
  53.    outp(0x3D5, Temp1);  /* restore original CRTC R33 setting */
  54.    /* If the register was writable, it's an ET4000 */
  55.    if ((Temp3 != 0x05) || (Temp2 != 0x0A)) return(0);
  56.  
  57.    /* See if a Sierra SC1148X Hicolor DAC is present by querying the
  58.       (presumably) ET4000-compatible BIOS. Not really necessary after
  59.       the hardware check above, but generally more useful; in the
  60.       future it will return information about other high-color DACs */
  61.    regset.x.ax = 0x10F1;   /* Get DAC Type BIOS function # */
  62.    int86(0x10, ®set, ®set); /* ask BIOS for the DAC type */
  63.    if (regset.x.ax != 0x0010) return(0); /* function not supported */
  64.    switch (regset.h.bl) {
  65.       case 0:  return(0);  /* normal DAC (non-Hicolor) */
  66.       case 1:  break;      /* Sierra SC1148X 15-bpp Hicolor DAC */
  67.       default: return(0);  /* other high-color DAC */
  68.    }
  69.  
  70.    /* Set Hicolor mode */
  71.    regset.x.ax = 0x10F0;   /* Set High-Color Mode BIOS function # */
  72.    regset.h.bl = Mode;     /* desired resolution */
  73.    int86(0x10, ®set, ®set); /* have BIOS enable Hicolor mode */
  74.    return (regset.x.ax == 0x0010); /* 1 for success, 0 for failure */
  75. }
  76.  
  77.  
  78.  
  79.  
  80. [LISTING TWO]
  81.  
  82. /* Demonstrates non-antialiased drawing in 640x480 Hicolor (32K color) mode on 
  83. an ET4000-based SuperVGA with a Sierra Hicolor DAC installed. Tested with 
  84. Borland C++ 2.0 in C mode in the small model. */
  85.  
  86. #include <conio.h>
  87. #include <dos.h>
  88. #include "polygon.h"
  89. /* Draws the polygon described by the point list PointList in color
  90.    Color, with all vertices offset by (x,y) */
  91. #define DRAW_POLYGON(PointList,Color,x,y) {                 \
  92.    Polygon.Length = sizeof(PointList)/sizeof(struct Point); \
  93.    Polygon.PointPtr = PointList;                            \
  94.    FillCnvxPolyDrvr(&Polygon, Color, x, y, DrawHCLineList);}
  95.  
  96. void main(void);
  97. extern int SetHCMode(int);
  98. extern int FillCnvxPolyDrvr(struct PointListHeader *, int, int, int,
  99.    void (*)());
  100. extern void DrawHCLineList(struct HLineList *, int);
  101. int BitmapWidthInBytes = 640*2; /* # of bytes per raster line */
  102.  
  103. void main()
  104. {
  105.    struct PointListHeader Polygon;
  106.    static struct Point Face0[] = {{396,276},{422,178},{338,88},{288,178}};
  107.    static struct Point Face1[] = {{306,300},{396,276},{288,178},{210,226}};
  108.    static struct Point Face2[] = {{338,88},{266,146},{210,226},{288,178}};
  109.    union REGS regset;
  110.  
  111.    /* Attempt to enable 640x480 Hicolor mode */
  112.    if (SetHCMode(0x2E) == 0)
  113.       { printf("No Hicolor DAC detected\n"); exit(0); };
  114.  
  115.    /* Draw the cube */
  116.    DRAW_POLYGON(Face0, 0x1F, 0, 0);       /* full-intensity blue */
  117.    DRAW_POLYGON(Face1, 0x1F << 5, 0, 0);  /* full-intensity green */
  118.    DRAW_POLYGON(Face2, 0x1F << 10, 0, 0); /* full-intensity red */
  119.    getch();    /* wait for a keypress */
  120.  
  121.    /* Return to text mode and exit */
  122.    regset.x.ax = 0x0003;   /* AL = 3 selects 80x25 text mode */
  123.    int86(0x10, ®set, ®set);
  124. }
  125.  
  126.  
  127.  
  128.  
  129. [LISTING THREE]
  130.  
  131. /* Draws all pixels in the list of horizontal lines passed in, in Hicolor 
  132. (32K color) mode on an ET4000-based SuperVGA. Uses a slow pixel-by-pixel 
  133. approach. Tested with Borland C++ 2.0 in C mode in the small model. */
  134.  
  135. #include <dos.h>
  136. #include "polygon.h"
  137. #define SCREEN_SEGMENT     0xA000
  138. #define GC_SEGMENT_SELECT  0x3CD
  139.  
  140. void DrawPixel(int, int, int);
  141. extern int BitmapWidthInBytes; /* # of pixels per line */
  142.  
  143. void DrawHCLineList(struct HLineList * HLineListPtr,
  144.       int Color)
  145. {
  146.    struct HLine *HLinePtr;
  147.    int Y, X;
  148.  
  149.    /* Point to XStart/XEnd descriptor for the first (top) horizontal line */
  150.    HLinePtr = HLineListPtr->HLinePtr;
  151.    /* Draw each horizontal line in turn, starting with the top one and
  152.       advancing one line each time */
  153.    for (Y = HLineListPtr->YStart; Y < (HLineListPtr->YStart +
  154.          HLineListPtr->Length); Y++, HLinePtr++) {
  155.       /* Draw each pixel in the current horizontal line in turn,
  156.          starting with the leftmost one */
  157.       for (X = HLinePtr->XStart; X <= HLinePtr->XEnd; X++)
  158.          DrawPixel(X, Y, Color);
  159.    }
  160. }
  161.  
  162. /* Draws the pixel at (X, Y) in color Color in Hicolor mode on an
  163.    ET4000-based SuperVGA */
  164. void DrawPixel(int X, int Y, int Color) {
  165.    unsigned int far *ScreenPtr, Bank;
  166.    unsigned long BitmapAddress;
  167.  
  168.    /* Full bitmap address of pixel, as measured from address 0 to
  169.       address 0xFFFFF. (X << 1) because pixels are 2 bytes in size */
  170.    BitmapAddress = (unsigned long) Y * BitmapWidthInBytes + (X << 1);
  171.    /* Map in the proper bank. Bank # is upper word of bitmap addr */
  172.    Bank = *(((unsigned int *)&BitmapAddress) + 1);
  173.    /* Upper nibble is read bank #, lower nibble is write bank # */
  174.    outp(GC_SEGMENT_SELECT, (Bank << 4) | Bank);
  175.    /* Draw into the bank */
  176.    FP_SEG(ScreenPtr) = SCREEN_SEGMENT;
  177.    FP_OFF(ScreenPtr) = *((unsigned int *)&BitmapAddress);
  178.    *ScreenPtr = (unsigned int)Color;
  179. }
  180.  
  181.  
  182.  
  183.  
  184. [LISTING FOUR]
  185.  
  186. ; Draws all pixels in the list of horizontal lines passed in, in
  187. ; Hicolor (32K color) mode on an ET4000-based SuperVGA. Uses REP STOSW
  188. ; to fill each line. Tested with TASM 2.0. C near-callable as: 
  189. ;      void DrawHCLineList(struct HLineList * HLineListPtr, int Color);
  190.  
  191. SCREEN_SEGMENT  equ     0a000h
  192. GC_SEGMENT_SELECT equ   03cdh
  193.  
  194. HLine   struc
  195. XStart  dw      ?       ;X coordinate of leftmost pixel in line
  196. XEnd    dw      ?       ;X coordinate of rightmost pixel in line
  197. HLine   ends
  198.  
  199. HLineList struc
  200. Lngth   dw      ?       ;# of horizontal lines
  201. YStart  dw      ?       ;Y coordinate of topmost line
  202. HLinePtr dw     ?       ;pointer to list of horz lines
  203. HLineList ends
  204.  
  205. Parms   struc
  206.                 dw      2 dup(?) ;return address & pushed BP
  207. HLineListPtr    dw      ?       ;pointer to HLineList structure
  208. Color           dw      ?       ;color with which to fill
  209. Parms   ends
  210.  
  211. ; Advances both the read and write windows to the next 64K bank.
  212. ; Note: Theoretically, a delay between IN and OUT may be needed under
  213. ; some circumstances to avoid accessing the VGA chip too quickly, but
  214. ; in actual practice, I haven't found any delay to be required.
  215. INCREMENT_BANK  macro
  216.         push    ax              ;preserve fill color
  217.         push    dx              ;preserve scan line start pointer
  218.         mov     dx,GC_SEGMENT_SELECT
  219.         in      al,dx           ;get the current segment select
  220.         add     al,11h          ;increment both the read & write banks
  221.         out     dx,al           ;set the new bank #
  222.         pop     dx              ;restore scan line start pointer
  223.         pop     ax              ;restore fill color
  224.         endm
  225.  
  226.         .model small
  227.         .data
  228.         extrn   _BitmapWidthInBytes:word
  229.         .code
  230.         public _DrawHCLineList
  231.         align   2
  232. _DrawHCLineList proc    near
  233.         push    bp              ;preserve caller's stack frame
  234.         mov     bp,sp           ;point to our stack frame
  235.         push    si              ;preserve caller's register variables
  236.         push    di
  237.         cld                     ;make string instructions inc pointers
  238.         mov     ax,SCREEN_SEGMENT
  239.         mov     es,ax   ;point ES to display memory for REP STOS
  240.         mov     si,[bp+HLineListPtr] ;point to the line list
  241.         mov     ax,[_BitmapWidthInBytes] ;point to the start of the
  242.         mul     [si+YStart]     ; first scan line on which to draw
  243.         mov     di,ax           ;ES:DI points to first scan line to
  244.         mov     al,dl           ; draw; AL is the initial bank #
  245.                                 ;upper nibble of AL is read bank #,
  246.         mov     cl,4            ; lower nibble is write bank # (only
  247.         shl     dl,cl           ; the write bank is really needed for
  248.         or      al,dl           ; this module, but it's less confusing
  249.                                 ; to point both to the same place)
  250.         mov     dx,GC_SEGMENT_SELECT
  251.         out     dx,al           ;set the initial bank
  252.         mov     dx,di           ;ES:DX points to first scan line
  253.         mov     bx,[si+HLinePtr] ;point to the XStart/XEnd descriptor
  254.                                 ; for the first (top) horizontal line
  255.         mov     si,[si+Lngth]   ;# of scan lines to draw
  256.         and     si,si           ;are there any lines to draw?
  257.         jz      FillDone        ;no, so we're done
  258.         mov     ax,[bp+Color]   ;color with which to fill
  259.         mov     bp,[_BitmapWidthInBytes] ;so we can keep everything
  260.                                 ; in registers inside the loop
  261.                                 ;***stack frame pointer destroyed!***
  262. FillLoop:
  263.         mov     di,[bx+XStart]  ;left edge of fill on this line
  264.         mov     cx,[bx+XEnd]    ;right edge of fill
  265.         sub     cx,di
  266.         jl      LineFillDone    ;skip if negative width
  267.         inc     cx              ;# of pixels to fill on this line
  268.         add     di,di           ;*2 because pixels are 2 bytes in size
  269.         add     dx,bp           ;do we cross a bank during this line?
  270.         jnc     NormalFill      ;no
  271.         jz      NormalFill      ;no
  272.                                 ;yes, there is a bank crossing on this
  273.                                 ; line; figure out where
  274.         sub     dx,bp           ;point back to start of line
  275.         add     di,dx           ;offset of left edge of fill
  276.         jc      CrossBankBeforeFilling ;raster splits before the left
  277.                                 ; edge of fill
  278.         add     cx,cx           ;fill width in bytes (pixels * 2)
  279.         add     di,cx           ;do we split during the fill area?
  280.         jnc     CrossBankAfterFilling ;raster splits after the right
  281.         jz      CrossBankAfterFilling ; edge of fill
  282.                                 ;bank boundary falls within fill area;
  283.                                 ; draw in two parts, one in each bank
  284.         sub     di,cx           ;point back to start of fill area
  285.         neg     di              ;# of bytes left before split
  286.         sub     cx,di           ;# of bytes to fill to the right of
  287.                                 ; the bank split
  288.         push    cx              ;remember right-of-split fill width
  289.         mov     cx,di           ;# of left-of-split bytes to fill
  290.         shr     cx,1            ;# of left-of-split words to fill
  291.         neg     di              ;offset at which to start filling
  292.         rep     stosw           ;fill left-of-split portion of line
  293.         pop     cx              ;get back right-of-split fill width
  294.         shr     cx,1            ;# of right-of-split words to fill
  295.                                 ;advance to the next bank       
  296.         INCREMENT_BANK          ;point to the next bank (DI already
  297.                                 ; points to offset 0, as desired)
  298.         rep     stosw           ;fill right-of-split portion of line
  299.         add     dx,bp           ;point to the next scan line
  300.         jmp     short CountDownLine ; (already advanced the bank)
  301. ;======================================================================
  302.         align   2               ;dfill area is entirely to the left of
  303. CrossBankAfterFilling:          ; the bank boundary
  304.         sub     di,cx           ;point back to start of fill area
  305.         shr     cx,1            ;CX = fill width in pixels
  306.         jmp     short FillAndAdvance ;doesn't split until after the
  307.                                 ; fill area, so handle normally
  308. ;======================================================================
  309.         align   2               ;fill area is entirely to the right of
  310. CrossBankBeforeFilling:         ; the bank boundary
  311.         INCREMENT_BANK          ;first, point to the next bank, where
  312.                                 ; the fill area resides
  313.         rep     stosw           ;fill this scan line
  314.         add     dx,bp           ;point to the next scan line
  315.         jmp     short CountDownLine ; (already advanced the bank)
  316. ;======================================================================
  317.         align   2               ;no bank boundary problems; just fill
  318. NormalFill:                     ; normally
  319.         sub     dx,bp           ;point back to start of line
  320.         add     di,dx           ;offset of left edge of fill
  321. FillAndAdvance:
  322.         rep     stosw           ;fill this scan line
  323. LineFillDone:
  324.         add     dx,bp           ;point to the next scan line
  325.         jnc     CountDownLine   ;didn't cross a bank boundary
  326.         INCREMENT_BANK          ;did cross, so point to the next bank 
  327. CountDownLine:
  328.         add     bx,size HLine   ;point to the next line descriptor
  329.         dec     si              ;count off lines to fill
  330.         jnz     FillLoop
  331. FillDone:
  332.         pop     di              ;restore caller's register variables
  333.         pop     si
  334.         pop     bp              ;restore caller's stack frame
  335.         ret
  336. ;======================================================================
  337. _DrawHCLineList endp
  338.         end
  339.  
  340.  
  341.  
  342.  
  343. [LISTING FIVE]
  344.  
  345. /* Demonstrates unweighted antialiased drawing in 640x480 Hicolor (32K color) 
  346. mode. Tested with Borland C++ 2.0 in C mode in the small model. */
  347.  
  348. #include <conio.h>
  349. #include <dos.h>
  350. #include <stdlib.h>
  351. #include <string.h>
  352. #include "polygon.h"
  353. /* Draws the polygon described by the point list PointList in the
  354.    color specified by RED, GREEN, AND BLUE, with all vertices
  355.    offset by (x,y), to ScanLineBuffer, at ResMul multiple of
  356.    horizontal and vertical resolution. The address of ColorTemp is
  357.    cast to an int to satisfy the prototype for FillCnvxPolyDrvr; this
  358.    trick will work only in a small data model */
  359. #define DRAW_POLYGON_HIGH_RES(PointList,RED,GREEN,BLUE,x,y,ResMul) { \
  360.    Polygon.Length = sizeof(PointList)/sizeof(struct Point);          \
  361.    Polygon.PointPtr = PointTemp;                                     \
  362.    /* Multiply all vertical & horizontal coordinates */              \
  363.    for (k=0; k<sizeof(PointList)/sizeof(struct Point); k++) {        \
  364.       PointTemp[k].X = PointList[k].X * ResMul;                      \
  365.       PointTemp[k].Y = PointList[k].Y * ResMul;                      \
  366.    }                                                                 \
  367.    ColorTemp.Red=RED; ColorTemp.Green=GREEN; ColorTemp.Blue=BLUE;    \
  368.    FillCnvxPolyDrvr(&Polygon, (int)&ColorTemp, x, y, DrawBandedList);}
  369. #define SCREEN_WIDTH 640
  370. #define SCREEN_SEGMENT 0xA000
  371.  
  372. void main(void);
  373. extern void DrawPixel(int, int, char);
  374. extern void DrawBandedList(struct HLineList *, struct RGB *);
  375. extern int SetHCMode(int);
  376.  
  377. /* Table of gamma corrected mappings of linear color intensities in
  378.    the range 0-255 to the nearest pixel values in the range 0-31,
  379.    assuming a gamma of 2.3 */
  380. static unsigned char ColorMappings[] = {
  381.     0, 3, 4, 4, 5, 6, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9,10,10,10,
  382.    10,10,11,11,11,11,11,12,12,12,12,12,13,13,13,13,13,13,14,14,
  383.    14,14,14,14,14,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,
  384.    17,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,18,19,19,
  385.    19,19,19,19,19,19,19,19,20,20,20,20,20,20,20,20,20,20,20,21,
  386.    21,21,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,22,22,
  387.    22,22,22,23,23,23,23,23,23,23,23,23,23,23,23,24,24,24,24,24,
  388.    24,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,25,25,25,
  389.    25,25,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,27,27,
  390.    27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,
  391.    28,28,28,28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,
  392.    29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,30,30,30,30,30,
  393.    30,30,30,30,30,30,31,31,31,31,31,31,31,31,31,31};
  394. /* Pointer to buffer in which high-res scanned data will reside */
  395. struct RGB *ScanLineBuffer;
  396. int ScanBandStart, ScanBandEnd;  /* top & bottom of each high-res
  397.                                   band we'll draw to ScanLineBuffer */
  398. int ScanBandWidth;      /* # subpixels across each scan band */
  399. int BitmapWidthInBytes = 640*2;  /* # of bytes per raster line in
  400.                                     Hicolor VGA display memory */
  401. void main()
  402. {
  403.    int i, j, k, m, Red, Green, Blue, jXRes, kXWidth;
  404.    int SubpixelsPerMegapixel;
  405.    unsigned int Megapixel, ResolutionMultiplier;
  406.    long BufferSize;
  407.    struct RGB ColorTemp;
  408.    struct PointListHeader Polygon;
  409.    struct Point PointTemp[4];
  410.    static struct Point Face0[] =
  411.          {{396,276},{422,178},{338,88},{288,178}};
  412.    static struct Point Face1[] =
  413.          {{306,300},{396,276},{288,178},{210,226}};
  414.    static struct Point Face2[] =
  415.          {{338,88},{266,146},{210,226},{288,178}};
  416.    int LeftBound=210, RightBound=422, TopBound=88, BottomBound=300;
  417.    union REGS regset;
  418.  
  419.    printf("Subpixel resolution multiplier:");
  420.    scanf("%d", &ResolutionMultiplier);
  421.    SubpixelsPerMegapixel = ResolutionMultiplier*ResolutionMultiplier;
  422.    ScanBandWidth = SCREEN_WIDTH*ResolutionMultiplier;
  423.  
  424.    /* Get enough space for one scan line scanned out at high
  425.       resolution horz and vert (each pixel is 4 bytes) */
  426.    if ((BufferSize = (long)ScanBandWidth*4*ResolutionMultiplier) >
  427.          0xFFFF) {
  428.       printf("Band won't fit in one segment\n"); exit(0); }
  429.    if ((ScanLineBuffer = malloc((int)BufferSize)) == NULL) {
  430.       printf("Couldn't get memory\n"); exit(0); }
  431.  
  432.    /* Attempt to enable 640x480 Hicolor mode */
  433.    if (SetHCMode(0x2E) == 0)
  434.       { printf("No Hicolor DAC detected\n"); exit(0); };
  435.  
  436.    /* Scan out the polygons at high resolution one screen scan line at
  437.       a time (ResolutionMultiplier high-res scan lines at a time) */
  438.    for (i=TopBound; i<=BottomBound; i++) {
  439.       /* Set the band dimensions for this pass */
  440.       ScanBandEnd = (ScanBandStart = i*ResolutionMultiplier) +
  441.             ResolutionMultiplier - 1;
  442.       /* Clear the drawing buffer */
  443.       memset(ScanLineBuffer, 0, BufferSize);
  444.       /* Draw the current band of the cube to the scan line buffer */
  445.       DRAW_POLYGON_HIGH_RES(Face0,0xFF,0,0,0,0,ResolutionMultiplier);
  446.       DRAW_POLYGON_HIGH_RES(Face1,0,0xFF,0,0,0,ResolutionMultiplier);
  447.       DRAW_POLYGON_HIGH_RES(Face2,0,0,0xFF,0,0,ResolutionMultiplier);
  448.  
  449.   /* Coalesce subpixels into normal screen pixels (megapixels) and draw them */
  450.       for (j=LeftBound; j<=RightBound; j++) {
  451.          jXRes = j*ResolutionMultiplier;
  452.          /* For each screen pixel, sum all the corresponding
  453.             subpixels, for each color component */
  454.          for (k=Red=Green=Blue=0; k<ResolutionMultiplier; k++) {
  455.             kXWidth = k*ScanBandWidth;
  456.             for (m=0; m<ResolutionMultiplier; m++) {
  457.                Red += ScanLineBuffer[jXRes+kXWidth+m].Red;
  458.                Green += ScanLineBuffer[jXRes+kXWidth+m].Green;
  459.                Blue += ScanLineBuffer[jXRes+kXWidth+m].Blue;
  460.             }
  461.          }
  462.          /* Calc each color component's average brightness; convert
  463.             that into a gamma corrected portion of a Hicolor pixel,
  464.             then combine the colors into one Hicolor pixel */
  465.          Red = ColorMappings[Red/SubpixelsPerMegapixel];
  466.          Green = ColorMappings[Green/SubpixelsPerMegapixel];
  467.          Blue = ColorMappings[Blue/SubpixelsPerMegapixel];
  468.          Megapixel = (Red << 10) + (Green << 5) + Blue;
  469.          DrawPixel(j, i, Megapixel);
  470.       }
  471.    }
  472.    getch();    /* wait for a keypress */
  473.  
  474.    /* Return to text mode and exit */
  475.    regset.x.ax = 0x0003;   /* AL = 3 selects 80x25 text mode */
  476.    int86(0x10, ®set, ®set);
  477. }
  478.  
  479.  
  480.  
  481.  
  482. [LISTING SIX]
  483.  
  484. /* Draws pixels from the list of horizontal lines passed in, to a 32-bpp 
  485. buffer; drawing takes place only for scan lines between ScanBandStart and 
  486. ScanBandEnd, inclusive; drawing goes to ScanLineBuffer, with the scan line at 
  487. ScanBandStart mapping to the first scan line in ScanLineBuffer. Note that 
  488. Color here points to an RGB structure that maps directly to the buffer's pixel 
  489. format, rather than containing a 16-bit integer. Tested with Borland C++ 2.0 
  490. in C mode in the small model */
  491.  
  492. #include "polygon.h"
  493.  
  494. extern struct RGB *ScanLineBuffer;  /* drawing goes here */
  495. extern int ScanBandStart, ScanBandEnd; /* limits of band to draw */
  496. extern int ScanBandWidth;  /* # of subpixels across scan band */
  497.    
  498. void DrawBandedList(struct HLineList * HLineListPtr,
  499.    struct RGB *Color)
  500. {
  501.    struct HLine *HLinePtr;
  502.    int Length, Width, YStart = HLineListPtr->YStart, i;
  503.    struct RGB *BufferPtr, *WorkingBufferPtr;
  504.  
  505.    /* Done if fully off the bottom or top of the band */
  506.    if (YStart > ScanBandEnd) return;
  507.    Length = HLineListPtr->Length;
  508.    if ((YStart + Length) <= ScanBandStart) return;
  509.  
  510.    /* Point to XStart/XEnd descriptor for the first (top) horizontal line */
  511.    HLinePtr = HLineListPtr->HLinePtr;
  512.  
  513.    /* Confine drawing to the specified band */
  514.    if (YStart < ScanBandStart) {
  515.       /* Skip ahead to the start of the band */
  516.       Length -= ScanBandStart - YStart;
  517.       HLinePtr += ScanBandStart - YStart;
  518.       YStart = ScanBandStart;
  519.    }
  520.    if (Length > (ScanBandEnd - YStart + 1))
  521.       Length = ScanBandEnd - YStart + 1;
  522.  
  523.    /* Point to the start of the first scan line on which to draw */
  524.    BufferPtr = ScanLineBuffer + (YStart-ScanBandStart)*ScanBandWidth;
  525.  
  526.    /* Draw each horizontal line within the band in turn, starting with
  527.       the top one and advancing one line each time */
  528.    while (Length-- > 0) {
  529.       /* Fill whole horiz line with Color if it has positive width */
  530.       if ((Width = HLinePtr->XEnd - HLinePtr->XStart + 1) > 0) {
  531.          WorkingBufferPtr = BufferPtr + HLinePtr->XStart;
  532.          for (i = 0; i < Width; i++) *WorkingBufferPtr++ = *Color;
  533.       }
  534.       HLinePtr++;                /* point to next scan line X info */
  535.       BufferPtr += ScanBandWidth; /* point to start of next line */
  536.    }
  537. }
  538.  
  539.  
  540.  
  541.  
  542. [LISTING SEVEN]
  543.  
  544. /* POLYGON.H: Header file for polygon-filling code */
  545.  
  546. /* Describes a single point (used for a single vertex) */
  547. struct Point {
  548.    int X;   /* X coordinate */
  549.    int Y;   /* Y coordinate */
  550. };
  551.  
  552. /* Describes a series of points (used to store a list of vertices that 
  553. describe a polygon; each vertex is assumed to connect to the two adjacent 
  554. vertices, and the last vertex is assumed to connect to the first) */
  555. struct PointListHeader {
  556.    int Length;                /* # of points */
  557.    struct Point * PointPtr;   /* pointer to list of points */
  558. };
  559.  
  560. /* Describes the beginning and ending X coordinates of a single
  561.    horizontal line */
  562. struct HLine {
  563.    int XStart; /* X coordinate of leftmost pixel in line */
  564.    int XEnd;   /* X coordinate of rightmost pixel in line */
  565. };
  566.  
  567. /* Describes a Length-long series of horizontal lines, all assumed to be on 
  568. contiguous scan lines starting at YStart and proceeding downward (used to 
  569. describe scan-converted polygon to low-level hardware-dependent drawing code)*/
  570. struct HLineList {
  571.    int Length;                /* # of horizontal lines */
  572.    int YStart;                /* Y coordinate of topmost line */
  573.    struct HLine * HLinePtr;   /* pointer to list of horz lines */
  574. };
  575.  
  576. /* Describes a color as an RGB triple, plus one byte for other info */
  577. struct RGB { unsigned char Red, Green, Blue, Spare; };
  578.  
  579.